BASIC PYTHON FOR RESEARCHERS

by Megat Harun Al Rashid bin Megat Ahmad
last updated: April 14, 2016


5. Functions and Modules


5.1 Functions

$Python$ has many built-in functions, e.g., $print$ format is a built-in $python$ function, so are the $sqrt$() function and the $\pi$ value which can be used by importing the $math$ library.

Available $python$ function can be used by importing its library usually at the start of the program.


In [1]:
# Find the square root of integer in a list

from math import *

x1 = [23,12,45]
for m,k in enumerate(x1):
    Ex1 = sqrt(k)
    print Ex1


4.79583152331
3.46410161514
6.7082039325

In the above example, all functions in the $math$ library are imported and these functions can be used directly with their original names. The library can also be imported as it is or by assigning it a different name. In these cases the function can only be used by writing the original library name or the assigned name followed by a dot (.) and the name of the function:


In [2]:
# Import just the original library name

import math

x1 = [23,12,45]
for m,k in enumerate(x1):
    Ex1 = math.sqrt(k)
    print Ex1


4.79583152331
3.46410161514
6.7082039325

In [3]:
# Import and reassign the library name

import math as mt

x1 = [23,12,45]
for m,k in enumerate(x1):
    Ex1 = mt.sqrt(k)
    print Ex1


4.79583152331
3.46410161514
6.7082039325

Sometimes, it is not necessary to import all available functions in a library as this increases memory usage. For instance to import just the $sqrt$() function from the $math$ library:


In [4]:
from math import sqrt

x1 = [23,12,45]
for z in range(0,len(x1),1):
    Ex1 = sqrt(x1[z])
    print Ex1


4.79583152331
3.46410161514
6.7082039325

The $sqrt$() function can also be assigned a different name, e.g. as $pkd$().


In [5]:
from math import sqrt as pkd

x1 = [23,12,45]
for z in range(0,len(x1),1):
    Ex1 = pkd(x1[z])
    print Ex1


4.79583152331
3.46410161514
6.7082039325

$Python$ user can also build their own functions and libraries. Function is defined by using the syntax $def$ followed by a space and the function name. A pair of round brackets must follow the function name. Function must be defined first before being called. If the function is to receive a variable pass by the caller then this variable must be named inside the pair of the round brackets (if more than one variable then for these variables, each must be separated by a comma). The function can return a value (if more than one value, each value needs to be separated by a comma) that resulted from the function process with syntax $return$ value back to the caller.

Now let us built our own square root function with a specific name such as $pk$.


In [6]:
# Find the square root of integer in a list
# using own defined function

def pk(arg1):
    result_pk = arg1**0.5
    return result_pk
    
x1 = [23,12,45]

for z in range(0,len(x1),1):
    Ex1 = pk(x1[z])
    print Ex1


4.79583152331
3.46410161514
6.7082039325

Here, the function $pk$ was first defined in the program in which it can accept a value (assigned to variable $arg1$). This value was later operated to produce the square root value (assigned to variable $result_pk$) and this was returned back to the caller. The function was called in the $for$ control structure with the elements of the list $x1$ passed to the function sequentially.

Here is another example on function that converts temperature value in Celcius to Fahreinheit:


In [7]:
# Celcius to Fahreinheit

def Fahreinheit(temp):
    temp = float(temp)
    temp = (temp*9/5)+32
    return temp

deg = u"\u00B0"

valC = input("Give the temperature Celcius: ")
valF = Fahreinheit(valC)
print ("The %3.2f%sC is equivalent to %3.2f%sF" % (valC,deg,valF,deg))


Give the temperature Celcius: 38
The 38.00°C is equivalent to 100.40°F

5.2 Modules

The function definition can be written on different $python$ file and can be imported i.e. just like a library. This is called a module. Let us create two files, one contains the function ("Temp.py") and the other is the main program that will call the function:


In [8]:
%%file Temp.py

#Temp.py
#Celcius to Fahreinheit

def Fahreinheit(temp):
    temp = float(temp)
    temp = (temp*9/5)+32
    return temp


Overwriting Temp.py

A text can be written to file in a _**Jupyter Notebook**_ input cell. This can be done by writing %% $file$ at the start of the cell followed by the file name. Upon executing the cell, this file will be created and all written texts after the line %% $file$ filename will be appended to the file.

To call the function $Fahreinheit$, we need to import the function into the main program from the module $Temp$.


In [9]:
from Temp import Fahreinheit as Fh

deg = u"\u00B0"

valC = input("Give the temperature in Celcius: ")
valF = Fh(valC)
print ("The %3.2f%sC is equivalent to %3.2f%sF" % (valC,deg,valF,deg))


Give the temperature in Celcius: 38
The 38.00°C is equivalent to 100.40°F

Example 5.1: Write a program that can receive input value in Celcius or Fahreinheit and transform the value into Fahreinheit and Celcius respectively. Create the calculating functions as import module.


In [10]:
%%file TempConv.py

# TempConv.py

# Celcius to Fahreinheit

def Fahreinheit(temp):
    temp = float(temp)
    temp = (temp*9/5)+32
    return temp

# Fahreinheit to Celcius

def Celcius(temp):
    temp = float(temp)
    temp = (temp-32)*5/9
    return temp


Overwriting TempConv.py

A variable in a function is a local variable, which means that it cannot be used outside the function. It also means that identical variable name can be used in other functions.


In [11]:
from TempConv import *

deg = u"\u00B0"

valC = input("Give the temperature in Celcius: ")
valF = Fahreinheit(valC)
print ("The %3.1f%sC is equivalent to %3.1f%sF" % (valC,deg,valF,deg))

valF = input("Give the temperature in Fahreinheit: ")
valC = Celcius(valF)
print ("The %3.1f%sF is equivalent to %3.1f%sC" % (valF,deg,valC,deg))


Give the temperature in Celcius: 31
The 31.0°C is equivalent to 87.8°F
Give the temperature in Fahreinheit: 77
The 77.0°F is equivalent to 25.0°C

In [12]:
from TempConv import *

deg = u"\u00B0" # assigning a variable to a unicode for degree symbol

TempType = raw_input("Which temperature you want to convert, \
Celcius or Fahreinheit (C or F) ")

TempType = TempType.upper()

if TempType == 'C':
    valC = input("Give the temperature in Celcius: ")
    valF = Fahreinheit(valC)
    print ("The %3.1f%sC is equivalent to %3.1f%sF" % (valC,deg,valF,deg))

elif TempType == 'F':
    valF = input("Give the temperature in Fahreinheit: ")
    valC = Celcius(valF)
    print ("The %3.1f%sF is equivalent to %3.1f%sC" % (valF,deg,valC,deg))
    
else:
    print "No or wrong type is given."


Which temperature you want to convert, Celcius or Fahreinheit (C or F) C
Give the temperature in Celcius: 28
The 28.0°C is equivalent to 82.4°F

Here we need to cyclically run the above program to get results from different inputs, for example to know the temperature values with different units for several towns in Malaysia.

There is however a different and better programming approach (but not necessarily true for all cases). This is called object-oriented programming.


5.3 Object-Oriented Programming

There is no straight-forward definition of object-oriented programming (OOP). In this tutorial, OOP can be viewed as a different ways of building functions with group of data built using it. It involves the usage of $class$ and interacting variables which are usually called $objects$.

$Class$ is similar to function $def$, but inside a defined $class$, functions can be defined (these functions are usually called methods). Let us create similar library $TempConv$ but this time in object oriented mode (the file is called "TempConvOO.py"):


In [13]:
%%file TempConvOO.py

# TempConvOO.py

"""Convert temperature to Celcius or Fahreinheit

    Attributes:
        temp: integer/floating value of input temperature
"""

class Convert(object):
    
    def __init__(self,temp):
        
        self.temp = float(temp)
    
    # Celcius to Fahreinheit
    def toFahreinheit(self):
        print "%.1f F" % ((self.temp*9/5)+32)

    # Fahreinheit to Celcius
    def toCelcius(self):
        print "%.1f C" % ((self.temp-32)*5/9)


Overwriting TempConvOO.py

In this library a class named $Convert$ (that can create object) is declared with three methods: __init__(), toFahreinheit() and toCelcius(). The __init__() is a special method that initializes a newly construct object when the $class$ is called. The first argument of __init__() is a must (here conventionally named as $self$) and function as a reference to instances or attributes of the object which can later be used by all the other methods (Instances or attributes are variables that can be used inside methods). These methods therefore must also have $self$ as first argument.

In this example, __init__() constructor must receive an input (the temperature value that is assigned to $temp$, the second variable or attribute). The $temp$ value is assigned to $self.temp$ and this instance can be used by all the methods. If it is not assigned to $self$.\_$attribute$\_ than it is just a local attribute which means it can only be used inside the method similar like local variable declared inside a function.

The TempConvOO file or library can now be imported:


In [14]:
from TempConvOO import Convert

The class $Convert$ was imported as it is, with all its methods. We now pass an argument (the value of temperature that needs to be converted) to the class $Convert$ that will convert it to Fahreinheit value.


In [15]:
Convert(30).toFahreinheit()


86.0 F

Logically the passing of the integer '30' above represents the temperature value of unit Celcius and this was converted to Fahreinheit '86.0'. This is indicated by the method toFahreinheit() of the class Convert. Syntactically, in one line, the invoking of this method can be done by passing the integer value to the class followed by a dot '.' and the name of the method. This can be pass to an object:


In [16]:
Klang = Convert(87)

Object of the class can be created by assigning the invoked class to it. In the above line, the object is the name of the city of Klang and the integer '87' was passed as temperature value in Fahreinheit. Any method from the class Convert can now be called by the name of this object followed by a dot '.' and the name of the method.


In [17]:
Klang.toCelcius()


30.6 C

In [18]:
Klang.toFahreinheit()


188.6 F

This seems incorrect as trying to convert back to Fahreinheit gives a different value from '87' as input. The library is therefore needs to be refined and it may be better when creating objects, apart from the value of the temperature, the unit of the temperature can also be passed to the class.

This issue is addressed in the example below with a new library. Here the library will be called from a folder named 'Tutorial5' and to call the library from this folder an empty file named as '__init__.py' needs to be created inside the folder.


In [19]:
%%file Tutorial5/__init__.py

#This an empty file


Overwriting Tutorial5/__init__.py

In [20]:
%%file Tutorial5/TempConvO1.py

# TempConvOO.py

"""Convert temperature to Celcius or Fahreinheit

    Attributes:
        temp: integer/floating value of input temperature
        unit: string of the temperature unit
"""

class Convert(object):
    
    def __init__(self,temp,unit):
        
        self.temp = float(temp)
        self.unit = unit
    
    # Celcius to Fahreinheit
    def toFahreinheit(self):
        
        if self.unit == 'Fahreinheit':
            print "%.1f F" % self.temp
        else:
            print "%.1f F" % ((self.temp*9/5)+32)

    # Fahreinheit to Celcius
    def toCelcius(self):
        
        if self.unit == 'Celcius':
            print "%.1f C" % self.temp
        else:
            print "%.1f C" % ((self.temp-32)*5/9)


Overwriting Tutorial5/TempConvO1.py

In this new library, the class Convert will now receives two attributes: temperature value and unit. Methods can now be called with this instance and produce correct outputs.


In [21]:
from Tutorial5.TempConvO1 import Convert
Klang = Convert(87, 'Fahreinheit')

Importing a library from folder requires writing the name of the folder followed by a '.' and the name of the library.


In [22]:
Klang.toCelcius()


30.6 C

In [23]:
Klang.toFahreinheit()


87.0 F

We can now build a group of data with this class. For instance the temperatures in Celcius for selected cities in Selangor, Malaysia. These group of data can be accessed and processed.


In [24]:
Rawang = Convert(77, 'Fahreinheit'); Bangi = Convert(32, 'Celcius'); 
Kapar = Convert(28, 'Celcius')

In [25]:
Rawang.toCelcius()


25.0 C

In [26]:
Kapar.toFahreinheit()


82.4 F

In [27]:
Bangi.toCelcius()


32.0 C

We can now easily access and process these objects after creating them without cyclically having to create and destroy the assigned value like in the last example of subtopic 5.2.

Example 5.2: Write a program that read a given file (WeatherData.txt) that contains the basic weather data of few selected towns in Selangor, Malaysia and create objects that contain all these data.


In [28]:
# Reading line data from file and pass it to a list

filehandle = open("Tutorial5/WeatherData.txt","r")
townWeather = filehandle.readlines()
filehandle.close()

In [29]:
# Check the content of the list

townWeather


Out[29]:
['\n',
 'Town Temperature(C) Condition Wind(km/hr) Precipitation(%)\n',
 '\n',
 'Klang 33.6 Clear 5 55\n',
 'Rawang 35.5 Haze 2 77\n',
 'Bangi 27.0 Rain 10 95\n',
 'Kapar 30.8 Cloudy 7 80']

In [30]:
%%file Tutorial5/Weather.py

# Weather.py

"""Weather conditions of selected towns in Selangor, Malaysia

    Attributes:
        temp: integer/floating value of temperature
        cond: string of weather condition
        wcond: integer/floating value of wind speed
        prep: integer/floating value of humidity
"""

class Weather(object):
    
    def __init__(self, datalist):
        
        self.temp = float(datalist[0])
        self.cond = datalist[1]
        self.wcond = int(datalist[2])
        self.prep = int(datalist[3])
    
    def changetemperature(self, temp):

        self.temp = float(temp)
        print "The temperature is %.1f%sC" % (self.temp,u"\u00B0")

    # New condition
    def changecondition(self, cond):
        self.cond = cond
        print "The condition is %s" % self.cond

    # New wind speed
    def changewindspeed(self, wcond):
        self.wcond = wcond
        print "The wind speed is %d km/hr" % self.wcond
        
    # New humidity
    def changehumidity(self, prep):
        self.prep = prep
        print "The humidity is %d%s" % (self.prep,u"\u0025")

    # Temperature
    def temperature(self):

        print "The temperature is %.1f%sC" % (self.temp,u"\u00B0")

    # Condition
    def condition(self):

        print "The condition is %s" % self.cond

    # Wind speed
    def windspeed(self):

        print "The wind speed is %d km/hr" % self.wcond
        
    # Humidity
    def humidity(self):

        print "The humidity is %d%s" % (self.prep,u"\u0025")


Overwriting Tutorial5/Weather.py

In [31]:
# Importing the Weather class as wt

from Tutorial5.Weather import Weather as wt

In [32]:
# Slicing the list

townWeather[3:]


Out[32]:
['Klang 33.6 Clear 5 55\n',
 'Rawang 35.5 Haze 2 77\n',
 'Bangi 27.0 Rain 10 95\n',
 'Kapar 30.8 Cloudy 7 80']

In [33]:
# Creating a two dimensional list

townWeather1 = []

for i,j in enumerate(townWeather[3:]):
    
    townWeather1 = townWeather1 + [j.replace('\n','').split()]

In [34]:
# Checking the content of the two dimensional list

townWeather1


Out[34]:
[['Klang', '33.6', 'Clear', '5', '55'],
 ['Rawang', '35.5', 'Haze', '2', '77'],
 ['Bangi', '27.0', 'Rain', '10', '95'],
 ['Kapar', '30.8', 'Cloudy', '7', '80']]

In [35]:
# Create a dictionary with keys as objects

town = {}
for i,j in enumerate(townWeather1):
    passobject = wt([j[1],j[2],j[3],j[4]])
    town[j[0]] = passobject

In [36]:
town


Out[36]:
{'Bangi': <Tutorial5.Weather.Weather at 0x7f2ed4096d90>,
 'Kapar': <Tutorial5.Weather.Weather at 0x7f2ed4096dd0>,
 'Klang': <Tutorial5.Weather.Weather at 0x7f2ed4096d10>,
 'Rawang': <Tutorial5.Weather.Weather at 0x7f2ed4096d50>}

In [37]:
town['Klang'].temperature()


The temperature is 33.6°C

In [38]:
town['Rawang'].humidity()


The humidity is 77%

In [39]:
town['Rawang'].changehumidity(98)


The humidity is 98%

In [40]:
town['Rawang'].humidity()


The humidity is 98%

More on functions and modules can be found on https://docs.python.org/2/tutorial/modules.html